typedef float real;

#include <vector>
//#define GLM_FORCE_SSE2 
//#define GLM_FORCE_INLINE 
#include <glm\glm.hpp>

class Shader;

class FluidSolver
{
	static const int MAX_PARTICLES = 1024*8;

	// The particle structure holding all of the relevant information.
	struct particle 
	{ 
		glm::vec2 pos;
		glm::vec2 pos_old;
		glm::vec2 vel;
		glm::vec2 force; 
		real rho, rho_near, press, press_near, sigma, beta; 
		real color;
		particle* succ;
		int id;
	};

private:
	int N;                     // Number of Particles in the simulation
	real G, spacing, k, k_near, rest_density, sigma, beta;
	real r, rsq, inv_r;
	// Our collection of particles
	int particlesCreated;

	// Mouse attractor
	glm::vec2 attractor;
	

	particle particles[MAX_PARTICLES];
	std::vector< glm::vec3 > verts;
	std::vector< glm::vec2 > attractors;
	std::vector<std::vector< float >> distance_field;

	
	void update_grid();
	void calc_density();
	void calc_viscosity();
	void calc_pressure();
	void advance_particles();

private:
	unsigned int VertexVBOID;
	unsigned int distance_field_tex;
	Shader *colorShader;
	bool paused;

	void generateColorLUT();

	
public:
	void initParticles();
	double uploadTime;
	int attracting, repelling;
	bool do_viscosity_step;
	float SIM_W;
	

	int grid_width, grid_height;
	std::vector< std::vector< particle* > > grid;
	FluidSolver();
	~FluidSolver();
	void render();
	void update();
	void activateAttractor( int x, int y );
	void deactivateAttractor();
	void addParticles( int x, int y );
	int getParticleCount() { return particlesCreated; }
	void activateRepelling( int mx, int my );
	void removeAllParticles() { particlesCreated = 0; }
	void reinstallShader();
	void togglePause(){ paused = !paused; }
};